<template>
  <ie-page :loading="loading" is-fixed>

    <template #extra>
      <n-space>
        <template v-if="data?.status === 0">
          <n-button @click="handleCancel">不予受理</n-button>
          <n-button type="primary" @click="handleAccept">受理事件</n-button>
        </template>
        <template v-if="data?.status === 2">
          <!-- <n-button @click="handleSave">暂存</n-button> -->
          <n-button
            type="primary"
            @click="handleProcess"
          >处理事件</n-button>
        </template>
      </n-space>
    </template>

    <template #header>
      <div
        class="ticket-header"
        v-if="data"
      >
        <h2>事件编号：{{ data.code }}</h2>
        <div class="ie-clearfix">
          <a-row :gutter="12">
            <a-col :span="8">
              <span>录入人员：</span>
              <span>{{ data.create_by?.nickname }}</span>
            </a-col>
            <a-col :span="8">
              <span>受理部门：</span>
              <span>{{ data.department?.name }}</span>
            </a-col>
            <a-col :span="8">
              <template v-if="data.accept_by?.nickname">
                <span>受理民警：</span>
                <span>{{ data.accept_by?.nickname }}</span>
              </template>
            </a-col>
            <a-col :span="8">
              <span>录入时间：</span>
              <span>{{ format(data.create_at) }}</span>
            </a-col>
            <a-col :span="8">
              <span>事件来源：</span>
              <span>{{ data.ticket_source?.content }}</span>
            </a-col>
          </a-row>
          <div class="ie-pullright">
            <span>事件状态</span>
            <span :class="[statusRef.type]">{{ statusRef.label }}</span>
          </div>
        </div>
      </div>
    </template>

    <div class="ticket-block">
      <div class="ticket-block--head">流程进度</div>
      <div class="ticket-block--body">
        <ie-timeline
          :steps-value="timelineRef"
          :steps="['事件录入', '事件审核', '事件调解', '完成']"
        />
      </div>
    </div>

    <div
      class="ticket-block"
      v-if="data"
    >
      <div class="ticket-block--head">事件信息</div>
      <div class="ticket-block--body">
        <table>
          <tr>
            <th>事件名称：</th>
            <td>{{ data.title }}</td>
          </tr>
          <tr>
            <th>事件详情：</th>
            <td>{{ data.content }}</td>
          </tr>
          <tr>
            <th>事件备注：</th>
            <td>{{ data.create_msg || '暂无' }}</td>
          </tr>
          <tr>
            <th>事件举证：</th>
            <td>
              <a-image-preview-group
                v-if="data?.attachments?.length"
                infinite
              >
                <a-space>
                  <div
                    class="file-box"
                    v-for="file in data.attachments"
                    :key="file.id"
                  >
                    <a-image
                      v-if="['.png', '.jpg', '.jpeg', '.webp'].indexOf(file.ext) > -1"
                      :src="file.filepath"
                      width="160"
                      height="160"
                    />
                    <div
                      v-else-if="['.pdf'].indexOf(file.ext) > -1"
                      class="file-box--file"
                      @click="openPdf(file.filepath, file.filename)"
                    >
                      <icon-file-pdf size="32" />
                      <span>{{ file.filename }}</span>
                    </div>
                    <div
                      v-else-if="['.mp4'].indexOf(file.ext) > -1"
                      class="file-box--file"
                      @click="openVideo(file.filepath, file.filename)"
                    >
                      <icon-file-video size="32" />
                      <span>{{ file.filename }}</span>
                    </div>
                    <div
                      v-else
                      class="file-box--file"
                      @click="openFile(file.id)"
                    >
                      <icon-file size="32" />
                      <span>{{ file.filename }}</span>
                    </div>
                  </div>
                </a-space>
              </a-image-preview-group>
              <span v-else>暂无</span>
            </td>
          </tr>
        </table>
      </div>
    </div>

    <div
      class="ticket-block"
      v-if="data?.status >= 2"
    >
      <div class="ticket-block--head">卷宗文档</div>
      <div class="ticket-block--body docx">
        <a-image-preview-group infinite>
          <a-space v-if="template.length" wrap>
            <div
              class="file-box"
              v-for="file in template"
              :key="file.id"
            >
              <a-image
                v-if="['.png', '.jpg', '.jpeg', '.webp'].indexOf(file.ext) > -1"
                :src="file.filepath"
                width="160"
                height="160"
              />
              <div
                v-else-if="file.ext === '.pdf'"
                class="file-box--file"
                @click="openPdf(file.filepath, file.filename)"
              >
                <icon-file-pdf size="18" />
                <span>{{ file.filename }}</span>
              </div>
              <div
                v-else
                class="file-box--file"
                @click="openFile(file.id)"
              >
                <icon-file size="18" />
                <span>{{ file.filename }}</span>
              </div>
            </div>
          </a-space>
          <span v-else>暂无</span>
        </a-image-preview-group>
      </div>
    </div>

    <template v-if="~[2, 3, 4, 5, 6, 7].indexOf(data?.status)">
      <div class="ticket-block">
        <div class="ticket-block--head">涉案材料</div>
        <div class="ticket-block--body">
          <a-upload
            :disabled="[4, 5, 6, 7].indexOf(data?.status) > -1"
            :show-remove-button="[4, 5, 6, 7].indexOf(data?.status) === -1"
            :action="uploadUrl"
            download
            :on-before-remove="onBeforeRemove"
            :headers="headers"
            :accept="uploadAccept"
            v-model:file-list="fileListRef"
            :custom-icon="customIcon"
          />
        </div>
      </div>

      <div class="ticket-block">
        <div class="ticket-block--head">待签字文档</div>
        <div class="ticket-block--body">
          <a-upload
            :disabled="[4, 5, 6, 7].indexOf(data?.status) > -1"
            :show-remove-button="[4, 5, 6, 7].indexOf(data?.status) === -1"
            :action="signUploadUrl"
            download
            :on-before-remove="onBeforeRemoveSign"
            :headers="headers"
            :accept="uploadSignAccept"
            v-model:file-list="fileListSignRef"
            :custom-icon="customIcon"
          />
        </div>
      </div>
    </template>

    <div
      class="ticket-block"
      v-if="~[4, 5, 6, 7].indexOf(data?.status)"
    >
      <div class="ticket-block--head">事件处理情况</div>
      <div class="ticket-block--body">
        <table>
          <tr>
            <th>事件状态：</th>
            <td :class="[statusRef.type]">
              <a-tag>{{ statusRef.label }}</a-tag>
            </td>
          </tr>
          <tr>
            <th>处理备注：</th>
            <td>{{ data.process_msg || '暂无' }}</td>
          </tr>
        </table>
      </div>
    </div>

    <div
      class="ticket-block"
      v-if="fileListSignRef.length"
    >
      <div class="ticket-block--head">签字区</div>
      <div class="ticket-block--body">
        <a-tabs position="right" v-if="enableRef">
          <a-tab-pane
            v-for="item in normalizeFileListSign(fileListSignRef)"
            :title="item.name"
            :key="item.id"
          >
            <a-list class="bookmark">
              <a-list-item
                v-for="(bookmark, $index) in item.bookmarks"
                :key="$index"
              >
                <BookmarkItem
                  v-model="bookmarkForm[item.id + bookmarkSymbol + bookmark]"
                  @update:modelValue="handleBookmarkChange"
                  :name="bookmark"
                />
              </a-list-item>
            </a-list>
            <div class="ie-pullright">
              <a-button
                type="primary"
                :disabled="!hasBookmark(item)"
                @click="download(item.id)"
                :loading="downloadLoading"
              >下载已签名的文档</a-button>
            </div>
          </a-tab-pane>
        </a-tabs>
        <a-alert
          v-else
          type="warning"
        >设备未连接，请检查</a-alert>
      </div>
    </div>

  </ie-page>
</template>

<script setup>
import { ref, computed, h, resolveComponent } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { cloneDeep } from 'lodash-es'
import { useMutation } from 'villus'
import { Modal } from '@arco-design/web-vue'
import { useMessage } from 'naive-ui'
import { IconFile, IconFilePdf, IconFileVideo } from '@arco-design/web-vue/es/icon'

import { useApi, getHeaders } from '/@/api'
import { useGraphqlClient } from '/@/graphql'
import { format, openWindow } from '/@/utils/helper'
import { TICKET_STATUS } from '/@/model/ticket'
import { SIGN_URL } from '/@/config'
import gql from 'graphql-tag'

import { useDialog } from '/@/components/dialog'
import { TYPE_IMAGE, TYPE_VIDEO, TYPE_OFFICE } from '/@/model/attachment'

import { BookmarkItem } from './modules/BookmarkItem'

const route = useRoute()
const router = useRouter()
const message = useMessage()
const api = useApi()

const id = route.params.id
const loading = ref(true)

function back() {
  router.push({ name: 'Ticket' })
}

if (!id) back()

const fileListRef = ref([])
const fileListSignRef = ref([])

const uploadUrl = `/api/system/ticket/${id}/upload`
const signUploadUrl = `/api/system/ticket/${id}/upload/sign`

const headers = ref()
const uploadAccept = [...TYPE_IMAGE, ...TYPE_VIDEO].join(',')
const uploadSignAccept = TYPE_OFFICE.join(',')

const template = ref([])
const bookmarkSymbol = '::::'
const bookmarkForm = ref({})

function getData() {
  api.get(`ticket/${id}`, null, { authorize: true })
    .then(res => {
      if (res.code === 0) {
        data.value = res.data
        headers.value = getHeaders()
        loading.value = false

        // 设置涉案材料
        fileListRef.value = (data.value?.attachments_pending || []).map(
          ({ id: pendingId, filepath, filename, create_at }) => {
            return {
              uid: pendingId,
              url: filepath,
              name: filename,
              status: 'done',
              create_at
            }
          }
        )

        // 设置待签字文档
        fileListSignRef.value = (data.value?.attachments_sign || []).map(
          ({ id: signId, filepath, filename, create_at, bookmarks = [] }) => {
            return {
              uid: signId,
              url: filepath,
              name: filename,
              status: 'done',
              create_at,
              bookmarks
            }
          }
        )

        // 设置签名
        bookmarkForm.value = (data.value?.bookmarks || []).reduce((prev, { id, bookmarks }) => {
          bookmarks.forEach(({ name, filepath }) => {
            prev[`${id}${bookmarkSymbol}${name}`] = filepath
          })
          return prev
        }, {})

        checkEnable()

        // 获取卷宗文档
        if (data.value?.department?.id) {
          useGraphqlClient().executeQuery({
            query: gql`
              query ($id: Int!) {
                template (
                  where: { department_id: { _eq: $id } }
                  order_by: { create_at: asc }
                ) {
                  id
                  bookmarks
                  attachment: ie_attachment {
                    id
                    filename
                    filepath
                    ext
                  }
                }
              }
            `,
            variables: { id: data.value.department.id }
          }).then(queryRes => {
            if (!queryRes.error) {
              const templateValue = []

              for (let item of queryRes.data.template) {
                templateValue.push(item?.attachment)
              }
              template.value = templateValue
            }
          })
        }
      } else {
        back()
      }
    })
}

const data = ref({})
const timelineRef = computed(() => {
  const timeline = []
  const create = (status, txt = '事件录入') => ({
    username: data.value.create_by?.nickname,
    time: data.value.create_at,
    status,
    txt
  })
  const accept = (status, txt = '事件审核') => ({
    username: data.value.accept_by?.nickname,
    time: data.value.accept_at,
    status,
    txt
  })
  const process = (status, txt = '事件调解') => ({
    username: data.value.process_by?.nickname,
    time: data.value.process_at,
    status,
    txt
  })

  switch (data.value.status) {
    case 0: {
      timeline.push(create(2), accept(0))
      break
    }
    case 1: {
      timeline.push(create(2), accept(1, '审核未通过'))
      break
    }
    case 2: {
      timeline.push(create(2), accept(2), process(0))
      break
    }
    case 3: {
      timeline.push(create(2), accept(2), process(0))
      break
    }
    case 4: {
      timeline.push(create(2), accept(2), process(1, '不予受理'))
      break
    }
    case 5: {
      timeline.push(create(2), accept(2), process(2), process(2, '已撤回'))
      break
    }
    case 6: {
      timeline.push(create(2), accept(2), process(2), process(1, '调解不成'))
      break
    }
    case 7: {
      timeline.push(create(2), accept(2), process(2), process(2, '已办结'))
      break
    }
  }

  return timeline
})

const statusRef = computed(() => {
  return TICKET_STATUS
    .find(o => o.value === data.value.status) || {
      label: '无'
    }
})

getData()

function openFile(id) {
  openWindow(`/api/viewer/${id}`)
}

function openPdf(src, filename) {
  openWindow(src, filename)
}

const VideoComp = resolveComponent('ie-video')

function openVideo(src, filename) {
  Modal.open({
    title: filename,
    content: () => h(VideoComp, {
      src
    }),
    width: 800,
    height: 600
  })
}

const dialogRef = useDialog()

function handleAccept() {
  dialogRef.accept({
    onClose: getData
  })
}

function handleCancel() {
  dialogRef.cancel({
    onClose: getData
  })
}

function handleProcess() {
  dialogRef.process({
    onClose: getData
  })
}

function handleSave() {}

function onChange(file, ...args) {
  console.log(file, args)
}

const { execute: remove } = useMutation(gql`
  mutation ($ticket_id: uuid!, $attachment_id: Int) {
    delete_ticket_attachments_pending (
      where: { _and: {
        ticket_id: { _eq: $ticket_id },
        attachment_id: { _eq: $attachment_id }
      } }
    ) {
      affected_rows
    }
  }
`)
const { execute: removeSign } = useMutation(gql`
  mutation ($ticket_id: uuid!, $attachment_id: Int) {
    delete_ticket_sign (
      where: { _and: {
        ticket_id: { _eq: $ticket_id },
        attachment_id: { _eq: $attachment_id }
      } }
    ) {
      affected_rows
    }
  }
`)

function getAttachmentId({ status, response, uid }) {
  if (status !== 'done') return
  if (response?.code === 0) {
    return response?.data?.id
  }
  return uid
}

function onBeforeRemove(file = {}) {
  const attachment_id = getAttachmentId(file)

  if (attachment_id) {
    return new Promise(resolve => {
      Modal.confirm({
        content: `确认删除 ${file.name} ?`,
        onOk: () => {
          remove({
            ticket_id: id,
            attachment_id
          }).then(() => resolve(true))
        },
        onCancel: () => resolve(false)
      })
    })
  }

  return true
}

function onBeforeRemoveSign(file = {}) {
  const attachment_id = getAttachmentId(file)

  if (attachment_id) {
    return new Promise(resolve => {
      Modal.confirm({
        content: `确认删除 ${file.name} ?`,
        onOk: () => {
          removeSign({
            ticket_id: id,
            attachment_id
          }).then(() => resolve(true))
        },
        onCancel: () => resolve(false)
      })
    })
  }

  return true
}

const customIcon = {
  fileName(file) {
    const children = [
      h('span', file.name)
    ]
    const create_at = file.create_at ||
      file?.response?.data?.create_at

    if (create_at) {
      children.push(
        h('span', { style: {
          marginLeft: '8px',
          fontSize: '12px',
          color: '#86909c'
        } }, `文件上传于 ${format(create_at)}`)
      )
    }

    return h('span', children)
  }
}

function normalizeFileListSign(fileList) {
  return fileList.map(file => {
    if (file?.response) {
      const { id, filename, bookmarks } = file.response?.data || {}

      return {
        id,
        name: filename,
        bookmarks
      }
    }
    const { uid, name, bookmarks = [] } = file

    return {
      id: uid,
      name,
      bookmarks
    }
  })
}

function hasBookmark(o) {
  return Array.isArray(o.bookmarks) &&
    o.bookmarks.some(bookmark => bookmark.filepath !== null)
}

const { execute: updateBookmark } = useMutation(gql`
  mutation ($id: uuid!, $object: ticket_set_input ) {
    update_ticket_by_pk (
      pk_columns: { id: $id }
      _set: $object
    ) {
      id
    }
  }
`)

function getFilename(id) {
  const files = cloneDeep(fileListSignRef.value)
  const normalized = normalizeFileListSign(files)
  const file = normalized.find(o => o.id === id)

  return file?.name
}

function handleBookmarkChange() {
  const clone = cloneDeep(bookmarkForm.value)
  const bookmarksValue = []

  Object.keys(clone).forEach(key => {
    const [id, name] = key.split(bookmarkSymbol)
    const item = bookmarksValue.find(o => o.id === id)
    const subItem = {
      name,
      filepath: clone[key]
    }

    if (Array.isArray(item?.bookmarks)) {
      item.bookmarks.push(subItem)
    } else {
      bookmarksValue.push({
        id,
        filename: getFilename(id),
        bookmarks: [subItem]
      })
    }
  })

  updateBookmark({ id, object: {
    bookmarks: bookmarksValue
  }})
}

const downloadLoading = ref(false)

function download(attachmentId) {
  const a = document.createElement('a')

  a.download = a.href = `/api/system/ticket/${id}/sign/${attachmentId}`
  document.body.appendChild(a)

  downloadLoading.value = true
  message.success('正在生成文档，请稍候')

  a.click()
  a.remove()

  setTimeout(() => {
    downloadLoading.value = false
  }, 5e3)
}

const enableRef = ref(false)

function checkEnable() {
  api.text('', {
    methodName: 'health'
  }, {
    prefixUrl: SIGN_URL,
    retry: 0,
    isText: true
  })
    .then(res => {
      enableRef.value = res === 'OK'
    })
    .catch(() => {})
}
</script>

<style lang="less">
.ticket-header {
  padding-top: 20PX;

  h2 {
    font-size: 18px;
    font-weight: normal;
    color: #33353C;
  }

  .ie-clearfix {
    font-size: 14px;
    color: #33353C;

    .arco-col {
      white-space: nowrap;
    }

    .arco-row {
      display: inline-flex;
    }

    span {
      display: inline-block;
      line-height: 1.5;
      margin-bottom: 8px;
      margin-right: 8px;
    }

    .ie-pullright {
      text-align: right;

      span {
        color: #C4C4C4;
        display: block;
        margin-bottom: 2px;

        & + span {
          font-size: 20px;
        }
      }

      .info {
        color: #4F8AFF;
      }

      .error {
        color: rgb(var(--danger-6));
      }

      .warning {
        color: rgb(var(--warning-6));
      }

      .success {
        color: rgb(var(--success-6));
      }
    }
  }
}

.ticket-block {
  background-color: #FFFFFF;
  border-radius: 8px;
  font-size: 16px;
  color: #33353C;
  border: 1px solid #EFEFF7;
  margin-bottom: 24px;

  &--head {
    padding: 14PX 24px;
    line-height: 24px;
    border-bottom: 1px solid #EFEFF7;
  }

  &--body {
    padding: 24px;
  }

  table {
    border-collapse: collapse;
    width: 100%;
    font-size: 14px;
    line-height: 24px;
    color: #33353C;

    th {
      font-weight: normal;
      white-space: nowrap;
      padding-right: 10px;
      padding-bottom: 16px;
      vertical-align: top;
    }

    td {
      padding-bottom: 16px;
      width: 100%;
    }
  }
}

.file-box {
  width: 160px;
  height: 160px;
  border: 1px solid #E0E0E5;
  box-sizing: border-box;
  overflow: hidden;

  &--file {
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    height: 100%;
    text-align: center;

    span {
      font-size: 12px;
      line-height: 18px;
      color: #888;
      display: inline-block;
      margin-top: 10px;
    }
  }
}

.docx {

  .arco-space {
    padding: 24px 32px 16px;
    background-color: #F5F5FA;
    border-radius: 4px;
    width: 100%;

    .arco-space-item {
      margin-right: 12px;
    }

    .file-box {
      height: auto;
      width: auto;
      border: 0;
      background: #FFFFFF;
      box-shadow: 0 2px 8px 0 rgb(20 37 63 / 8%);
      border-radius: 4px;
      padding: 0 16px;
      cursor: pointer;

      .file-box--file {
        display: inline-block;

        span {
          font-size: 14px;
          margin-top: 0;
          line-height: 36px;
          color: #207FF0;
        }

        .arco-icon {
          vertical-align: text-bottom;
          color: #207FF0;
          margin-right: 4px;
        }
      }
    }
  }
}

.bookmark {
  margin-bottom: 20px;
  min-width: 300px;
}
</style>